package com.tanhua.server.serivce;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.db.User;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class MovementsService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private UserApi userApi;

    @Autowired
    private UserStatusService userStatusService;

    @Autowired
    private MqMessageService messageService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 发布动态（保存动态信息）
     * @param textContent  ：文字内容
     * @param imageContent ；图片文件
     */
    public void movements(String textContent, MultipartFile[] imageContent) throws IOException {
        //1、获取用户id
        Long userId = UserHolder.getUserId();
        //根据UserId查询用户信息
        User user = userApi.findById(userId);
        //判断该用户的发布动态权限是否被冻结,如果被冻结,抛出发布动态冻结异常
        Boolean movementFreeze = userStatusService.findMovementFreeze(user);
        if (movementFreeze) {
            throw new BusinessException(ErrorResult.freezeMovementError());
        }
        //2、将图片上传到阿里云oss
        List<String> medias = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String imageUrl = ossTemplate.upload(multipartFile.getOriginalFilename(),
                    multipartFile.getInputStream());
            medias.add(imageUrl);
        }
        //3、构建Movement对象
        Movement movement = new Movement();
        movement.setUserId(userId);
        movement.setMedias(medias);
        movement.setTextContent(textContent);
        movement.setCreated(System.currentTimeMillis());
        //4、调用API保存数据
        String movementId=movementApi.save(movement);

        //5、发送一条MQ消息消息内容动态id   内容审核
        messageService.sendAudiService(movementId);//动态id
    }


    //查询我的动态:根据userId查询Movement
    //PageResult   --- List<MovementVo>
    public PageResult findByUserId(Integer page, Integer pagesize, Long userId) {
        //1、调用API根据userId分页查询Movement  List<Movement>
        List<Movement> list = movementApi.findByUserId(page,pagesize,userId);
        if(CollUtil.isEmpty(list)) {
            return new PageResult(); //前端页面要求，如果list集合不存在，需要返回一个空的PageResult
        }
        //2、根据用户id，查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        //3、将List<Movement>构造成 List<MovementVo>
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : list) {
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            //如果当前用户已经对其点赞，设置hasLiked=1
            String key = Constants.MOVEMENTS_INTERACT_KEY+movement.getId();
            String hashkey  = Constants.MOVEMENT_LIKE_HASHKEY + userId;
            Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashkey);//判断是否有hashKey
            if(hasKey) {
                vo.setHasLiked(1);
            }
            vos.add(vo);
        }
        //4、封装PageResult返回
        return new PageResult(page,pagesize,0l,vos);
    }

    /**
     * 查询我可见的所有动态（好友动态）
     *    根据friendId查询
     */
    public PageResult findByFriendId(Integer page, Integer pagesize) {
        //1、获取当前用户id
        Long friendId = UserHolder.getUserId();
        //2、调用API，根据friendId分页查询好友的动态列表 List<Movement>
        List<Movement> list = movementApi.findByFriendId(page,pagesize,friendId);
        if(CollUtil.isEmpty(list)) {
            return new PageResult();
        }
        //3、调用公共的方法
        return initPageResult(page,pagesize,list);
    }

    /**
     * 查询推荐好友
     *   1、新用户而言：没有推荐数据，随机获取几条动态展示
     *   2、老用户而言：有推荐数据
     *      2.1 从redis中获取推荐数据（动态id的字符串，多个之间通过“，”隔开）
     *          key ：MOVEMENTS_RECOMMEND_用户id
     *      2.2 查询mongodb，获取动态详情
     */
    public PageResult findByRecommend(Integer page, Integer pagesize) {
        //1、获取用户id
        String key = "MOVEMENTS_RECOMMEND_"+UserHolder.getUserId();
        //2、从redis中查询数据
        String values = redisTemplate.opsForValue().get(key);
        List<Movement> list = new ArrayList<>();
        if(StringUtils.isEmpty(values)) {
            //2.1 如果redis中数据不存在（新用户），调用API随机查询动态详情
            list = movementApi.randomMovement(pagesize);
        }else {
            //2.2 如果Reids中数据存在，根据动态id，查询动态详情
            String[] movementIds = values.split(","); //查询条件  ,1,2,3,4,5,6xxxxxxx,100
            list =  movementApi.findByIds(movementIds,page,pagesize);
        }
        //3、调用公共的方法
        return initPageResult(page,pagesize,list);
    }

    //公共的方法
    private PageResult initPageResult(Integer page, Integer pagesize,List<Movement> list) {
        //获取所有的发布人id
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //一次性查询所有发布人的详情  map
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds);

        //3、将List<Movement>构造成 List<MovementVo>
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : list) {
            //获取动态的发布人
            Long userId = movement.getUserId();
            //调用API查询发布人的用户详情
            UserInfo userInfo = map.get(userId);  //调用提供者，调用了多次。
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            //设置是否点赞
            String key = Constants.MOVEMENTS_INTERACT_KEY+movement.getId();
            String hashkey  = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
            Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashkey);//判断是否有hashKey
            if(hasKey) {
                vo.setHasLiked(1);
            }
            vos.add(vo);
        }
        //4、封装PageResult返回
        return new PageResult(page,pagesize,0l,vos);
    }


    //根据id查询动态详情
    public MovementsVo findMovementById(String movementId) {
        //1、调用api查询：Movement对象
        Movement movement = movementApi.findById(movementId);
        //2、构造MovementsVo
        UserInfo userInfo = userInfoApi.findById(movement.getUserId());
        return MovementsVo.init(userInfo,movement);
    }

    //点赞
    public Integer like(String movementId) {
        //1、判断用户是否对此动态已点赞  --查询MongoDB
        Integer commentType = 1;
        Boolean hasComment = commentApi.hasComment(movementId,UserHolder.getUserId(),commentType);
        //2、如果已经点赞，抛出异常
        if(hasComment) { //数据存在
            throw new BusinessException(ErrorResult.likeError());
        }
        //3、构造Comment对象，存入MongoDB
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(commentType);
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        //需要修改
        Integer count = commentApi.save(comment); //点赞之后的总数
        //4、将数据存入到Redis中
        //操作hash ， key   hashkey  -- hashvalue
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key,hashKey,"1");

        //5、发送日志消息
        messageService.sendLogService(UserHolder.getUserId(),"0203","movement",movementId);
        return count;
    }

    //取消点赞，返回总数
    public Integer dislike(String movementId) {
        //1、判断是否已经点赞
        Long userId = UserHolder.getUserId();
        Integer commentType = 1; //点赞
        Boolean hasComment = commentApi.hasComment(movementId,userId,commentType);
        //2、如果未点赞，抛出异常
        if(!hasComment) {
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //3、调用api删除MongoDB中的数据，返回删除之后的总点赞数
        Integer count = commentApi.delete(movementId,userId,commentType);
        //4、删除redis中的数据
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
        redisTemplate.opsForHash().delete(key,hashKey);//删除hash中的某个hashkey

        //5、发送日志消息
        messageService.sendLogService(UserHolder.getUserId(),"0206","movement",movementId);
        return count;
    }

    //喜欢
    public Integer love(String movementId) {
        //1、判断用户是否对此动态已点赞  --查询MongoDB
        Integer commentType = 3;
        Boolean hasComment = commentApi.hasComment(movementId,UserHolder.getUserId(),commentType);
        //2、如果已经喜欢，抛出异常
        if(hasComment) { //数据存在
            throw new BusinessException(ErrorResult.loveError());
        }
        //3、构造Comment对象，存入MongoDB
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(commentType);
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        Integer count = commentApi.save(comment); //点赞之后的总数
        //4、将数据存入到Redis中
        //操作hash ， key   hashkey  -- hashvalue
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key,hashKey,"1");

        messageService.sendLogService(UserHolder.getUserId(),"0204","movement",movementId);
        return count;
    }

    //取消喜欢
    public Integer unlove(String movementId) {
        //1、判断是否已经点赞
        Long userId = UserHolder.getUserId();
        Integer commentType = 3; //点赞
        Boolean hasComment = commentApi.hasComment(movementId,userId,commentType);
        //2、如果未点赞，抛出异常
        if(!hasComment) {
            throw new BusinessException(ErrorResult.disloveError());
        }
        //3、调用api删除MongoDB中的数据，返回删除之后的总点赞数
        Integer count = commentApi.delete(movementId,userId,commentType);
        //4、删除redis中的数据
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
        redisTemplate.opsForHash().delete(key,hashKey);//删除hash中的某个hashkey
        messageService.sendLogService(UserHolder.getUserId(),"0207","movement",movementId);
        return count;
    }
    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 首页访客记录
     */
    public List<TodayBest> visitors() {
        Long userId = UserHolder.getUserId();
        //1、从redis中获取当前用户，查看历史访客列表的时间  k-v
        String key = Constants.VISITORS_USER+userId;
        String str = redisTemplate.opsForValue().get(key);  //时间-毫秒数
        Long time = 0l;
        if(!StringUtils.isEmpty(str)) {//判断从redis里面查的数据是否存在如果存在转化为时间
            time = Long.valueOf(str);
        }
        //2、调用API，根据用户id和时间查询最新的5条访客数据 List<Visitors>
        List<Visitors> list = visitorsApi.findByUserId(userId,time);
        if(CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //根据visitorUserId访问人的id
        List<Long> ids = CollUtil.getFieldValues(list, "visitorUserId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids);
        //3、将 List<Visitors>转化为List<TodayBest>
        List<TodayBest> vos = new ArrayList<>();
        for (Visitors visitors : list) {
            UserInfo userInfo = map.get(visitors.getVisitorUserId());
            TodayBest vo = TodayBest.init(userInfo, visitors);
            vos.add(vo);
        }
        //4、返回
        return vos;
    }
}
